package com.example.literj.kt.internal.schedulers

import com.example.literj.kt.core.Scheduler
import com.example.literj.kt.disposables.Disposable
import com.example.literj.kt.disposables.DisposableContainer
import com.example.literj.kt.internal.disposables.EmptyDisposable
import com.example.literj.kt.plugins.RxJavaPlugins
import java.util.concurrent.*

open class NewThreadWorker(threadFactory: ThreadFactory) : Scheduler.Worker(), Disposable {
    private var executor: ScheduledExecutorService? = null

    init {
        executor = SchedulerPoolFactory.create(threadFactory)
    }

    @Volatile
    var disposed = false

    override fun schedule(run: Runnable): Disposable {
        return schedule(run, 0, null)
    }

    override fun schedule(run: Runnable?, delay: Long, unit: TimeUnit?): Disposable {
        return if (disposed) {
            EmptyDisposable.INSTANCE
        } else scheduleActual(run, delay, unit, null)
    }

    fun scheduleActual(
        run: Runnable?,
        delayTime: Long, unit: TimeUnit?,
        parent: DisposableContainer?
    ): ScheduledRunnable {
        val decoratedRun: Runnable = RxJavaPlugins.onSchedule(run)
        val sr = ScheduledRunnable(decoratedRun, parent)
        if (parent != null) {
            if (!parent.add(sr)) {
                return sr
            }
        }
        val f: Future<*>
        try {
            f = if (delayTime <= 0) {
                executor!!.submit(sr as Callable<*>)
            } else {
                executor!!.schedule(sr as Callable<Any>, delayTime, unit)
            }
            sr.setFuture(f)
        } catch (ex: RejectedExecutionException) {
            parent?.remove(sr)
            RxJavaPlugins.onError(ex)
        }
        return sr
    }

    fun shutdown() {
        if (!disposed) {
            disposed = true
            executor?.shutdown()
        }
    }

    override fun dispose() {
        if (!disposed) {
            disposed = true
            executor?.shutdownNow()
        }
    }

    override fun isDisposed() = disposed
}